﻿#pragma once

#include <map>

#include <xy/ais/context.h>

#include "renderer.h"
#include "shader.h"

class Context
{
  public:
    enum Texture
    {
        Yellow2d,
        White2d,
        Red2d,
        Green2d,
        Blue2d,
        Black2d,
        Chess,
        Dash,
        Snipple,
        Background
    };

    struct FrameData
    {
        unsigned int frameID;
        unsigned int textureID;
        unsigned int RBO;
    };

    /**
     * @brief 指针构造函数
     *
     * @param[in] hwnd
     */
    Context(int hwnd, int width, int height);

    /**
     * @brief 析构
     *
     */
    ~Context();

    /**
     * @brief 生成着色器
     *
     * @param[in] i
     * @param[in] geom
     */
    void gen_shader(std::string i, bool geom = false);

    /**
     * @brief 绑定着色器
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool bind_shader(std::string i);

    /**
     * @brief 移除着色器
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool remove_shader(std::string i);

    /**
     * @brief 加载顶点数据
     *
     * @param[in] i
     */
    void gen_array(int i);

    /**
     * @brief 绑定顶点数据
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool bind_array(int i);

    /**
     * @brief 加载索引数据
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool bind_ins_array(int i);

    /**
     * @brief 移除顶点数据
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool remove_array(int i);

    /**
     * @brief 解除绑定顶点数据
     *
     */
    void unbind_array();

    /**
     * @brief 生成 uniform 缓冲对象
     *
     * @param[in] i
     */
    void gen_UBO(int i);

    /**
     * @brief 绑定 uniform 缓冲对象
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool bind_UBO(int i);

    /**
     * @brief 移除 uniform 缓冲对象
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool remove_UBO(int i);

    /**
     * @brief 解除绑定 uniform 缓冲对象
     *
     */
    void unbind_UBO();

    /**
     * @brief 创建纹理
     *
     * @param[in] i
     */
    void gen_tex(int i);

    /**
     * @brief 加载 1D 纹理
     *
     * @param[in] texture
     * @param[in] a
     */
    void load_tex1d(Texture texture, float a = 1.0);

    /**
     * @brief 加载 2D 纹理
     *
     * @param[in] file
     */
    void load_tex2d(const char *file);

    /**
     * @brief 加载 2D 纹理
     *
     * @param[in] texture
     */
    void load_tex2d(Texture texture);

    /**
     * @brief 加载 3D 纹理
     *
     * @param[in] files
     */
    void load_tex3d(std::vector<const char *> files);

    /**
     * @brief 激活纹理
     *
     * @param[in] i
     */
    void activate_tex(int i);

    /**
     * @brief 绑定纹理
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool bind_tex1d(int i);

    /**
     * @brief 绑定纹理
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool bind_tex2d(int i);

    /**
     * @brief 绑定纹理
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool bind_tex3d(int i);

    /**
     * @brief 移除纹理
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool remove_tex(int i);

    /**
     * @brief 解除绑定纹理
     *
     */
    void unbind_tex();

    /**
     * @brief 生成帧缓冲对象
     *
     * @param[in] i
     * @param[in] w
     * @param[in] h
     */
    void gen_frame(int i, int w, int h);

    /**
     * @brief 绑定帧缓冲对象
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool bind_frame(int i);

    /**
     * @brief 获得帧缓冲对象纹理 ID
     *
     * @param[in] i
     * @return unsigned int
     */
    unsigned int frame_tex(int i);

    /**
     * @brief 移除帧缓冲对象
     *
     * @param[in] i
     * @return true
     * @return false
     */
    bool remove_frame(int i);

    /**
     * @brief 解除绑定帧缓冲对象
     *
     */
    void unbind_frame();

    /**
     * @brief 绘制
     *
     * @param[in] width
     * @param[in] height
     */
    void draw(int width, int height) const;

    /**
     * @brief 获得当前着色器
     *
     * @return std::shared_ptr<Shader>
     */
    std::shared_ptr<Shader> shader() const;

    /**
     * @brief 获得上下文对象
     *
     * @return std::shared_ptr<context>
     */
    std::shared_ptr<context> context() const;

    /**
     * @brief 获得 GLFW 窗口
     *
     * @return GLFWwindow*
     */
    GLFWwindow *window() const;

    /**
     * @brief 消息循环
     *
     * @return int
     */
    int message_loop();

  protected:
    std::map<int, unsigned int> m_VAOs;                       // 顶点数组对象 ID
    std::map<int, unsigned int> m_VBOs;                       // 顶点缓冲对象 ID
    std::map<int, unsigned int> m_EBOs;                       // 索引缓冲对象 ID
    std::map<int, unsigned int> m_Inss;                       // 实例缓冲对象 ID
    std::map<int, unsigned int> m_UBOs;                       // uniform 缓冲对象 ID
    std::map<int, unsigned int> m_textures;                   // 2D 纹理 ID
    std::map<int, FrameData> m_frames;                        // 帧缓冲对象 ID
    std::map<std::string, std::shared_ptr<Shader>> m_shaders; // 保存着色器

    std::shared_ptr<Shader> m_shader; // 当前着色器
    GLFWwindow *m_window;             // GLFW 窗口
};
